package edu.gmu.streams;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * A StreamOutputStream writes primitive Java numbers
 * and characters to an output stream in a big-endian format.
 * <p>
 * This class uses the traditional stream approach instead of block approach.
 *
 * @author  James H. Pope
 * @version $Revision:$ $Date:$
 */
public class StreamOutputStream implements BlockOutputStream
{
    private static final byte ZERO  = 0x00;
    
    //private int written = 0;
    private DataOutputStream out = null;
  
    
    /**
     * Creates a new StreamOutputStream and chains it to the output
     * stream specified by the out argument.
     * @param  out the underlying output stream.
     */
    public StreamOutputStream( ByteArrayOutputStream out )
    {
        this.out = new DataOutputStream(out);
    }
    
    /**
     * Skips the number of bytes ahead as indicated.
     * @param num bytes to skip
     */
    public void skipBytes(int skip) throws IOException
    {
        // Not so efficient - but gets the job done
        for (int i = 0; i < skip; i++)
        {
            this.out.write(ZERO); // ignore return, write a zero byte
        }
    }

    /**
     * Writes byte from underlying stream.
     * @param b
     * @throws java.io.IOException
     */
    public void writeByte( byte b ) throws IOException
    {
        this.out.write(b);
    }
    
    /**
     * Writes boolean (1-byte) to underlying stream.
     * @param b
     * @throws java.io.IOException
     */
    public void writeBoolean( boolean b ) throws IOException
    {
        this.out.writeBoolean( b );
    }
    
    /**
     * Writes short to underlying stream as two bytes.
     * @param s
     * @throws java.io.IOException
     */
    public void writeShort( short s ) throws IOException
    {
        this.out.writeShort(s);
    }
    
    /**
     * Writes short to underlying stream as four bytes.
     * @param i
     * @throws java.io.IOException
     */
    public void writeInt( int i ) throws IOException
    {
        this.out.writeInt(i);
    }
    
    /**
     * Writes short to underlying stream as eight bytes.
     * @param l
     * @throws java.io.IOException
     */
    public void writeLong( long l ) throws IOException
    {
        this.out.writeLong(l);
    }
    
    /**
     * Writes short to underlying stream as four bytes.
     * @param f
     * @throws java.io.IOException
     */
    public void writeFloat( float f ) throws IOException
    {
        this.out.writeFloat(f);
    }
    
    /**
     * Writes short to underlying stream as eight bytes.
     * @param d
     * @throws java.io.IOException
     */
    public void writeDouble( double d ) throws IOException
    {
        this.out.writeDouble(d);
    }
    
    /**
     * Writes variable length (2-byte length header) of UTF characters to
     * the underlying stream. 
     * @param String
     * @throws java.io.IOException
     */
    public void writeUTF( String s ) throws IOException
    {
        this.out.writeUTF(s);
    }
    
    
    /**
     * Bulk transfers bytes from given array to this buffer.
     * @param bytes
     * @throws java.io.IOException
     */
    public void write( byte[] bytes ) throws IOException
    {
        this.out.write(bytes);
    }
    
    /**
     * Bulk transfers booleans from given array to this buffer.
     * Implemenations may fall back to loop-calling writeBoolean().
     * @param booleans
     * @throws java.io.IOException
     */
    public void write( boolean[] booleans ) throws IOException
    {
        for (int i = 0; i < booleans.length; i++)
        {
            this.out.writeBoolean( booleans[i] );
        }
    }
    
    /**
     * Bulk transfers shorts from given array to this buffer.
     * @param shorts
     * @throws java.io.IOException
     */
    public void write( short[] shorts ) throws IOException
    {
        for (int i = 0; i < shorts.length; i++)
        {
            this.out.writeShort( shorts[i] );
        }
    }
    
    /**
     * Bulk transfers integers from given array to this buffer.
     * @param integers
     * @throws java.io.IOException
     */
    public void write( int[] integers ) throws IOException
    {
        for (int i = 0; i < integers.length; i++)
        {
            this.out.writeInt( integers[i] );
        }
    }
  
    /**
     * Bulk transfers floats from given array to this buffer.
     * @param floats
     * @throws java.io.IOException
     */
    public void write( float[] floats ) throws IOException
    {
        for (int i = 0; i < floats.length; i++)
        {
            this.out.writeFloat( floats[i] );
        }
    }
    
    /**
     * Bulk transfers longs from given array to this buffer.
     * @param longs
     * @throws java.io.IOException
     */
    public void write( long[] longs ) throws IOException
    {
        for (int i = 0; i < longs.length; i++)
        {
            this.out.writeLong( longs[i] );
        }
    }
    
    /**
     * Bulk transfers doubles from given array to this buffer.
     * @param doubles
     * @throws java.io.IOException
     */
    public void write( double[] doubles ) throws IOException
    {
        for (int i = 0; i < doubles.length; i++)
        {
            this.out.writeDouble( doubles[i] );
        }
    }
    
    /**
     * Bulk transfers strings from given array to this buffer.
     * Implemenations may fall back to loop-calling writeUTF().
     * @param strings
     * @throws java.io.IOException
     */
    public void write( String[] strings ) throws IOException
    {
        for (int i = 0; i < strings.length; i++)
        {
            this.writeUTF( strings[i] );
        }
    }
  

} //end ByteBufferOutputStream
